package com.example.exodemo;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.UriPermission;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.content.ContentUris;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.documentfile.provider.DocumentFile; // 推荐使用 DocumentFile

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private static final int READ_EXTERNAL_STORAGE_REQUEST_CODE = 1;
    private static final String TAG = "MainActivity"; // 日志标签
    private static final String PREFS_NAME = "MyMusicPrefs";
    private static final String KEY_MUSIC_ROOT_URI = "musicRootUri";

    private Button btnSelectMusicFolder;
    private Button btnClearMusicFolder; // 新增：清除已选目录
    private ListView lvAudioFiles;
    private ArrayList<AudioFileItem> audioFileItems; // 自定义类，包含名称和URI
    private ArrayAdapter<AudioFileItem> audioFilesAdapter;

    private Uri currentMusicRootUri;

    // ActivityResultLauncher for selecting a directory tree
    private final ActivityResultLauncher<Uri> openDirectoryLauncher =
            registerForActivityResult(new ActivityResultContracts.OpenDocumentTree(), treeUri -> {
                if (treeUri != null) {
                    Log.i(TAG, "Directory selected: " + treeUri);
                    // Take persistable URI permission
                    final int takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
                                         // | Intent.FLAG_GRANT_WRITE_URI_PERMISSION; // if you need write
                    getContentResolver().takePersistableUriPermission(treeUri, takeFlags);

                    // Save the URI
                    saveMusicRootUri(treeUri);
                    currentMusicRootUri = treeUri;
                    loadAudioFilesFromTree(currentMusicRootUri);
                    Toast.makeText(this, "音乐文件夹已选择", Toast.LENGTH_SHORT).show();
                    updateUI();
                } else {
                    Log.w(TAG, "No directory selected");
                }
            });


    // ActivityResultLauncher for selecting a single audio file (fallback, or alternative)
    private final ActivityResultLauncher<Intent> openAudioFileLauncher =
            registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
                if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
                    Uri audioUri = result.getData().getData();
                    if (audioUri != null) {
                        try {
                            getContentResolver().takePersistableUriPermission(audioUri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
                        } catch (SecurityException e) {
                            Log.e(TAG, "Failed to take persistable URI permission for audio file: " + e.getMessage());
                        }

                        // For single file, LRC finding is trickier if not in a known tree
                        // You'd need a more complex way to find its parent or ask for LRC separately
                        // This example focuses on the Document Tree approach for automatic LRC finding.
                        // Here, we'll just try to find LRC if we have a root tree.
                        Uri lrcUri = null;
                        if (currentMusicRootUri != null) {
                            // This is a simplified attempt, a robust solution would involve more complex matching
                            // or knowing the parent document URI of the selected audioUri.
                            String audioFileName = getFileNameFromDocumentUri(this, audioUri);
                            if (audioFileName != null) {
                                String lrcFileName = getBaseName(audioFileName) + ".lrc";
                                // This assumes audioUri is a child of currentMusicRootUri which might not be true
                                // if selected via ACTION_OPEN_DOCUMENT.
                                // A proper implementation would need to navigate from audioUri's parent.
                                // For now, let's assume we can search from root.
                                lrcUri = findFileInDocumentTree(this, currentMusicRootUri, lrcFileName, null);
                            }
                        }

                        Intent playerIntent = new Intent(this, PlayerActivity.class);
                        playerIntent.setData(audioUri);
                        if (lrcUri != null) {
                            playerIntent.putExtra("lrcUri", lrcUri); // Pass Document URI
                        }
                        startActivity(playerIntent);
                    }
                }
            });


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_saf); // Assume a new layout

        btnSelectMusicFolder = findViewById(R.id.btn_select_music_folder_saf);
        btnClearMusicFolder = findViewById(R.id.btn_clear_music_folder_saf);
        lvAudioFiles = findViewById(R.id.lv_audio_files_saf);

        audioFileItems = new ArrayList<>();
        audioFilesAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, audioFileItems);
        lvAudioFiles.setAdapter(audioFilesAdapter);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    READ_EXTERNAL_STORAGE_REQUEST_CODE);
        }

        btnSelectMusicFolder.setOnClickListener(v -> openDirectoryLauncher.launch(null)); // Pass null for initial path

        btnClearMusicFolder.setOnClickListener(v -> {
            clearMusicRootUri();
            currentMusicRootUri = null;
            audioFileItems.clear();
            audioFilesAdapter.notifyDataSetChanged();
            updateUI();
            Toast.makeText(this, "音乐文件夹选择已清除", Toast.LENGTH_SHORT).show();
        });

        // Load saved root URI
        currentMusicRootUri = loadSavedMusicRootUri();
        if (currentMusicRootUri != null) {
            // Check if permission is still valid
            if (hasPersistedUriPermission(currentMusicRootUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)) {
                Log.i(TAG, "Loaded saved music root URI: " + currentMusicRootUri);
                loadAudioFilesFromTree(currentMusicRootUri);
            } else {
                Log.w(TAG, "Permission for saved URI " + currentMusicRootUri + " no longer valid. Clearing.");
                clearMusicRootUri();
                currentMusicRootUri = null;
            }
        }
        updateUI();


        lvAudioFiles.setOnItemClickListener((parent, view, position, id) -> {
            AudioFileItem selectedItem = audioFileItems.get(position);
            if (selectedItem.getUri() != null && currentMusicRootUri != null) {
                // Find LRC file for this audio file within the selected tree
                String lrcFileName = getBaseName(selectedItem.getFileName()) + ".lrc";

                // We need the parent document URI of the selected audio file to search in the same directory
                // This is a bit simplified. A robust way is to use DocumentFile.getParentFile()
                DocumentFile audioDocFile = DocumentFile.fromSingleUri(this, selectedItem.getUri());
                Uri parentDocumentUri = null;
                if (audioDocFile != null && audioDocFile.getParentFile() != null) {
                    parentDocumentUri = audioDocFile.getParentFile().getUri();
                } else {
                    // Fallback to searching from root, less precise
                    parentDocumentUri = currentMusicRootUri;
                    Log.w(TAG,"Could not get parent for audio file, searching LRC from root: " + selectedItem.getFileName());
                }


                Uri lrcUri = findFileInDocumentTree(this, parentDocumentUri, lrcFileName, null);

                Intent playerIntent = new Intent(this, PlayerActivity.class);
                playerIntent.setData(selectedItem.getUri()); // Audio Document URI
                if (lrcUri != null) {
                    playerIntent.putExtra("lrcUri", lrcUri); // LRC Document URI
                    Log.i(TAG, "LRC Document URI found: " + lrcUri);
                } else {
                    Log.i(TAG, "LRC file not found for: " + selectedItem.getFileName());
                }
                startActivity(playerIntent);
            }
        });

        // Example: Add a button to select a single audio file as an alternative
        Button btnSelectSingleAudio = findViewById(R.id.btn_select_single_audio_saf); // Add to your layout
        btnSelectSingleAudio.setOnClickListener(v -> {
            Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("audio/*");
            openAudioFileLauncher.launch(intent);
        });
    }

    private void updateUI() {
        if (currentMusicRootUri != null) {
            btnSelectMusicFolder.setText("音乐文件夹已选 (更改)");
            btnClearMusicFolder.setVisibility(View.VISIBLE);
            lvAudioFiles.setVisibility(View.VISIBLE);
        } else {
            btnSelectMusicFolder.setText("选择音乐文件夹");
            btnClearMusicFolder.setVisibility(View.GONE);
            lvAudioFiles.setVisibility(View.GONE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == READ_EXTERNAL_STORAGE_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "存储权限已授予", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "需要存储权限来选择文件", Toast.LENGTH_SHORT).show();
            }
        }
    }

    private void saveMusicRootUri(Uri treeUri) {
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putString(KEY_MUSIC_ROOT_URI, treeUri.toString());
        editor.apply();
    }

    private Uri loadSavedMusicRootUri() {
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        String uriString = prefs.getString(KEY_MUSIC_ROOT_URI, null);
        return uriString != null ? Uri.parse(uriString) : null;
    }

    private void clearMusicRootUri() {
        SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.remove(KEY_MUSIC_ROOT_URI);
        editor.apply();

        // Release persisted URI permissions if any (optional, but good practice)
        if (currentMusicRootUri != null) {
            try {
                final int releaseFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
                //                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
                getContentResolver().releasePersistableUriPermission(currentMusicRootUri, releaseFlags);
                Log.i(TAG, "Released persisted URI permission for: " + currentMusicRootUri);
            } catch (SecurityException e) {
                Log.e(TAG, "Failed to release persisted URI permission: " + e.getMessage());
            }
        }
    }

    private boolean hasPersistedUriPermission(Uri uri, int modeFlags) {
        ContentResolver resolver = getContentResolver();
        List<UriPermission> persistedPermissions = resolver.getPersistedUriPermissions();
        for (UriPermission permission : persistedPermissions) {
            if (permission.getUri().equals(uri) &&
                (modeFlags == Intent.FLAG_GRANT_READ_URI_PERMISSION ? permission.isReadPermission() : false) ||
                (modeFlags == Intent.FLAG_GRANT_WRITE_URI_PERMISSION ? permission.isWritePermission() : false) ||
                 ((modeFlags & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) ==
                         (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION) &&
                                 permission.isReadPermission() && permission.isWritePermission())) {
                return true;
            }
        }
        return false;
    }


    private void loadAudioFilesFromTree(Uri treeUri) {
        audioFileItems.clear();
        // Using DocumentFile API is generally easier for tree traversal
        DocumentFile rootDir = DocumentFile.fromTreeUri(this, treeUri);
        if (rootDir != null && rootDir.isDirectory()) {
            Log.i(TAG, "Root directory: " + rootDir.getName() + ", Can read: " + rootDir.canRead());
            listFilesRecursively(rootDir, ""); // Pass empty string for initial relative path
        } else {
            Log.e(TAG, "Could not get DocumentFile from tree URI or it's not a directory: " + treeUri);
            Toast.makeText(this, "无法读取所选目录", Toast.LENGTH_SHORT).show();
        }
        audioFilesAdapter.notifyDataSetChanged();
        if (audioFileItems.isEmpty()){
            Toast.makeText(this,"在所选目录中未找到音频文件", Toast.LENGTH_SHORT).show();
        }
    }

    private void listFilesRecursively(DocumentFile parentDir, String relativePath) {
        if (parentDir == null || !parentDir.canRead()) return;

        for (DocumentFile file : parentDir.listFiles()) {
            if (file.isDirectory()) {
                Log.d(TAG, "Entering directory: " + file.getName());
                listFilesRecursively(file, relativePath + file.getName() + "/");
            } else if (file.isFile()) {
                String fileName = file.getName();
                String mimeType = file.getType(); // Get MIME type
                Log.d(TAG, "File: " + fileName + ", MIME: " + mimeType + ", URI: " + file.getUri());

                // Check if it's an audio file (you can be more specific with MIME types)
                if (mimeType != null && mimeType.startsWith("audio/")) {
                     // Or check by extension: fileName.endsWith(".mp3") || fileName.endsWith(".wav") etc.
                    audioFileItems.add(new AudioFileItem(fileName, file.getUri()));
                }
            }
        }
    }

    /**
     * Finds a file with a specific name within a given document tree (or a sub-directory).
     * @param context Context
     * @param parentDocumentUri The URI of the parent document (can be the root tree URI or a sub-directory URI)
     * @param targetFileName The exact name of the file to find (e.g., "song.lrc")
     * @param targetMimeType Optional: The MIME type to match (e.g., "text/plain" or "application/octet-stream" for LRC)
     * @return The Document URI of the found file, or null if not found.
     */
    @Nullable
    public static Uri findFileInDocumentTree(Context context, Uri parentDocumentUri, String targetFileName, @Nullable String targetMimeType) {
        if (parentDocumentUri == null || targetFileName == null) {
            return null;
        }

        DocumentFile parentDoc = DocumentFile.fromTreeUri(context, parentDocumentUri);
        if (parentDoc == null || !parentDoc.isDirectory() || !parentDoc.canRead()) {
            // If parentDocumentUri is not the root, it might be a single document URI.
            // In that case, we can't directly list its children using fromTreeUri.
            // This method assumes parentDocumentUri IS a directory within the tree.
            // If parentDocumentUri is from DocumentFile.getParentFile().getUri(), it should work.
             parentDoc = DocumentFile.fromSingleUri(context, parentDocumentUri);
             if (parentDoc == null || !parentDoc.isDirectory() || !parentDoc.canRead()){
                 Log.w(TAG, "findFileInDocumentTree: Parent URI is not a readable directory: " + parentDocumentUri);
                 return null;
             }
        }
        Log.d(TAG, "Searching for '" + targetFileName + "' in directory: " + (parentDoc.getName() != null ? parentDoc.getName() : parentDocumentUri));

        for (DocumentFile file : parentDoc.listFiles()) {
            if (file.isFile() && targetFileName.equals(file.getName())) {
                if (targetMimeType == null || targetMimeType.equals(file.getType())) {
                    Log.i(TAG, "Found target file: " + file.getName() + " with URI: " + file.getUri());
                    return file.getUri();
                }
            }
        }
        Log.i(TAG, "Target file '" + targetFileName + "' not found in directory: " + (parentDoc.getName() != null ? parentDoc.getName() : parentDocumentUri));
        return null;
    }


    /**
     * Gets the display name of a document URI.
     */
    public static String getFileNameFromDocumentUri(Context context, Uri uri) {
        if (uri == null) return null;
        String fileName = null;
        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            try (Cursor cursor = context.getContentResolver().query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)) {
                if (cursor != null && cursor.moveToFirst()) {
                    int displayNameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                    if (displayNameIndex != -1) {
                        fileName = cursor.getString(displayNameIndex);
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "Error getting file name from content URI: " + uri, e);
            }
        }
        if (fileName == null) {
            // Fallback for some URIs or if DocumentFile API is preferred for consistency
            DocumentFile docFile = DocumentFile.fromSingleUri(context, uri);
            if (docFile != null) {
                fileName = docFile.getName();
            }
        }
        return fileName;
    }

    /**
     * Gets the base name of a file (without extension).
     */
    public static String getBaseName(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex > 0) {
            return fileName.substring(0, dotIndex);
        }
        return fileName;
    }

    // Custom class to hold audio file info
    static class AudioFileItem {
        private final String fileName;
        private final Uri uri;

        public AudioFileItem(String fileName, Uri uri) {
            this.fileName = fileName;
            this.uri = uri;
        }

        public String getFileName() {
            return fileName;
        }

        public Uri getUri() {
            return uri;
        }

        @NonNull
        @Override
        public String toString() {
            return fileName; // This is what shows in the ArrayAdapter
        }
    }
}
